import { Provide,Inject,FORMAT,Task } from '@midwayjs/decorator';
import { RedisService } from '@midwayjs/redis';
import { DBBase } from '../base/DBBase';
import { Repository,In } from 'typeorm';
import { UserPartner } from '../entity/userPartner.entity';
import { IPagingData } from '../interfaces/IBase.interface';
import { PartnerInfo } from '../entity/partnerInfo.entity';
import { PartnerGroupStatus, PartnerStatus, UserAddendType, UserPartnerStatus } from '../interfaces/IPartner.interface';
import { PayService } from './pay.service';
import { ErrCode } from '../common/ErrCode';
import { IJsapiClientPay, IWechatErrResult } from '../interfaces/IWechat.interface';
import { Tools } from '../common/Tools';
import { Validate } from '@midwayjs/validate';
import { PartnerInfoDTO, QueryPartnerDTO } from '../dto/partner.dto';
import { CurrencyLogType, IUserPartnerProject } from '../interfaces/IUser.interface';
import { PartnerType } from '../entity/partnerType.entity';
import { partnerGroupBuy } from '../entity/partnerGroupBuy.entity';
import { UserService } from './user.service';
import { IBaseConfig, SystemConfigType } from '../interfaces/ISystem.interface';
import { SystemConfigService } from './system.service';

@Provide()
export class PartnerService extends DBBase{
    @Inject()
    userService:UserService;

    @Inject()
    wechatPay:PayService;

    @Inject()
    redisService:RedisService;

    @Inject()
    systemConfig:SystemConfigService;

    @Task({
        repeat: { cron: FORMAT.CRONTAB.EVERY_PER_5_SECOND}
    })
    public async autoEndGroup(){
        let partnerRep:Repository<partnerGroupBuy> = await this.Repository({entities:partnerGroupBuy});
        let list:partnerGroupBuy[] = await partnerRep.find({select:['id','endtime','status','partnerid','userids'], order:{id:'desc'},where:{status:PartnerGroupStatus.Ongoing}});
        if(list.length > 0){
            let grouplist:partnerGroupBuy[] = [];
            for(let i in list){
                if(list[i].endtime <= Tools.timestamp){
                    grouplist.push(list[i]);
                }
            }
            if(grouplist.length > 0){
                let userids:number[] = [];
                let partnerids:number[] = [];
                //结束拼团
                for(let g in grouplist){
                    grouplist[g].status = PartnerGroupStatus.Ended;
                    partnerids.push(grouplist[g].partnerid);
                    userids = userids.concat(grouplist[g].userids.split(',').map(Number));
                }
                let nUserids:number[] = userids.filter((item,index,userids)=>{
                    return userids.indexOf(item,0) == index;
                })
                try {
                    await partnerRep.save(grouplist); 
                } catch (error) {
                    
                }
                //用户项目信息结束
                let userPartnerList:UserPartner[] = await this.getUserPartnerByUserids(nUserids,UserPartnerStatus.Paid);
                let waitUpateUserPartnerList:UserPartner[] = userPartnerList.filter((item)=>{
                    return  partnerids.indexOf(item.partnerId) != -1;
                });
                let userpartnerRep:Repository<UserPartner> = await this.Repository({entities:UserPartner});

                try {
                     //退款
                    grouplist.map((item)=>{
                        this.refundPartner(item.partnerid,item.userids.split(',').map(Number));
                    });
                    waitUpateUserPartnerList.map((item)=>{
                        item.status = UserPartnerStatus.Refund;
                    })
                    await userpartnerRep.save(waitUpateUserPartnerList);
                } catch (error) {
                    
                }
            }
        }
    }

    public async addPartnerType(name:string):Promise<ErrCode>{
        let typeRep:Repository<PartnerType> = await this.Repository({entities:PartnerType});
        let typeinfo:PartnerType = await typeRep.findOne({where:{name:name}});
        if(typeinfo == null){
            typeinfo = new PartnerType();
            typeinfo.name = name;
            try {
                await typeRep.insert(typeinfo);
                return ErrCode.SYSTEM_SUCCESS;
            } catch (error) {
                return ErrCode.SYSTEM_FAIL;
            }
        }else{
            return ErrCode.Partner_type_name_repeat;
        }
    }
    public async GetPartnerTypeById(typeid:number):Promise<string|ErrCode>{
        let rep:Repository<PartnerType> = await this.Repository({entities:PartnerType});
        let info:PartnerType = await rep.findOne({where:{id:typeid}});
        if(info != null){
            return info.name;
        }else{
            return ErrCode.PARTNER_TYPE_NOT_FOUND;
        }
    }
    public async GetPartnerTypeList():Promise<PartnerType[]>{
        let rep:Repository<PartnerType> = await this.Repository({entities:PartnerType});
        let list:PartnerType[] = await rep.find();
        return list;
    }

    
    public async addUserPartner(partnerid:number,userid:number,status:UserPartnerStatus,appendData:number,appendType:UserAddendType/** = UserPartnerStatus.Wait_Paid*/):Promise<any>{
        if(appendType == UserAddendType.Invalid){
            return ErrCode.SYSTEM_SUCCESS;
        }
        let partners:Repository<UserPartner> = await this.Repository({entities:UserPartner});
        let partner:UserPartner = await partners.findOne({where:{partnerId:partnerid,userid:userid,status:UserPartnerStatus.Paid}});//确认单项目是否有未完成的操作
        if(partner == null){
            partner = new UserPartner();
            partner.addtime = Tools.timestamp;
            partner.partnerId = partnerid;
            partner.userid = userid;
            partner.status = status;
            partner.appendData = appendData;
            partner.appendType = appendType;
            try {
                await partners.insert(partner);
                return ErrCode.SYSTEM_SUCCESS;
            } catch (error) {
                return ErrCode.SYSTEM_FAIL;
            }
        }else{
            return ErrCode.SYSTEM_FAIL;
        }
    }

    public async updateUserPartnerStatus(userid:number[],partnerid:number,updateStatus:UserPartnerStatus,queryStatus:UserPartnerStatus):Promise<any>{
        let partners:Repository<UserPartner> = await this.Repository({entities:UserPartner});
        let partner:UserPartner[] = await partners.find({where:{partnerId:partnerid,userid:In(userid),status:queryStatus}});
        if(partner != null){
            partner.map((item)=>{
                item.status = updateStatus;
            });
            try {
                await partners.save(partner);
                if(queryStatus == UserPartnerStatus.Wait_Paid && partner.length == 1){
                    //支付成功后，更新加入或开团的 结果
                    let info:UserPartner = partner[0];
                    switch(info.appendType){
                        case UserAddendType.OpenGroup:
                            this.openGroup(info.userid,info.appendData,UserAddendType.Invalid);
                            break;
                        case UserAddendType.JoinGroup:
                            this.joinGroupByid(info.userid,info.appendData,UserAddendType.Invalid);
                            break;
                    }
                }
                return ErrCode.SYSTEM_SUCCESS;
            } catch (error) {
                return ErrCode.SYSTEM_FAIL;
            }
        }else{
            return ErrCode.SYSTEM_FAIL;
        }
    }
    public async getUserPartnerByUserids(userids:number[],status:UserPartnerStatus):Promise<UserPartner[]>{
        let partners:Repository<UserPartner> = await this.Repository({entities:UserPartner});
        let partner:UserPartner[] = await partners.find({where:{userid:In(userids),status:status}});
        return partner;
    }

    public async getUserPartnerByStatus(userid:number,status:UserPartnerStatus):Promise<UserPartner[]>{
        let partners:Repository<UserPartner> = await this.Repository({entities:UserPartner});
        let partner:UserPartner[] = await partners.find({where:{userid:userid,status:status}});
        return partner;
    }

    public async getUserPartnerInfo(userid:number):Promise<IUserPartnerProject>{
        let userPartnerRep:Repository<UserPartner> = await this.Repository({entities:UserPartner});
        let partnerInfoRep:Repository<PartnerInfo> = await this.Repository({entities:PartnerInfo});
        let pro:IUserPartnerProject = {
            payment:[],
            toCommunicate:[],
            completed:[]
        }
        let userPartner:UserPartner[] = await userPartnerRep.find({select:['id','status','partnerId','paidId'],where:{userid:userid}});
        let partnerIdList:number[] = [];
        for(let i in userPartner){
            switch(userPartner[i].status){
                case UserPartnerStatus.Wait_Paid:
                    pro.payment.push(userPartner[i].paidId);
                    break;
                case UserPartnerStatus.Paid:
                    partnerIdList.push(userPartner[i].partnerId);
                    break;
            }
        }
        if(partnerIdList.length > 0){
            let partnerList:PartnerInfo[] = await partnerInfoRep.find({select:['id','status'],where:{id:In(partnerIdList)}});
            if(partnerList.length > 0){
                for(let p in partnerList){
                    switch(partnerList[p].status){
                        case PartnerStatus.Ongoing:
                            break;
                        case PartnerStatus.Interview:
                            pro.toCommunicate.push(partnerList[p].id);
                            break;
                        case PartnerStatus.Ended:
                            pro.completed.push(partnerList[p].id);
                            break;
                    }
                }
            }
        }
        return pro;
    }

     public async getUserPartner(userid:number,paging:IPagingData):Promise<UserPartner[]>{
        let partners:Repository<UserPartner> = await this.Repository({entities:UserPartner});
        let partner:UserPartner[] = await partners.find({where:{userid:userid},order:{id:'desc'},skip:((paging.page-1)*paging.limit),take:paging.limit});
        return partner;
    }

    /**添加新项目 */
    @Validate()
     public async addPartnerInfo(info:PartnerInfoDTO):Promise<ErrCode>{
        let partnerRep:Repository<PartnerInfo> = await this.Repository({entities:PartnerInfo});
        let partner:PartnerInfo = await partnerRep.findOne({where:{name:info.name}});
        if(info.id != null){
            partner = await partnerRep.findOne({where:{id:info.id}});
        }
        if(partner == null){
            partner = new PartnerInfo();
            partner.name = info.name;
            partner.serialNo = "P"+Tools.makeNumberId(17)+'-'+Tools.makeRandomNum(6)+"-"+Tools.makeRandomNum(6);
            partner.typeId = info.typeId;
            
            partner.addtime = Tools.timestamp;
            partner.min = info.min;
            partner.max = info.max;
            partner.now = 0;
            partner.joinFee = info.joinFee;
            partner.des = info.des;
            partner.thumbnailImage = JSON.stringify(info.thumbnailImage);
            partner.detailsImage = JSON.stringify(info.detailsImage);

            partner.groupEnable = info.groupEnable;
            partner.groupNum = info.groupNum;
            partner.groupAging = info.groupAging;
            try {
                await partnerRep.insert(Tools.formatData(partner));
                return ErrCode.SYSTEM_SUCCESS;
            } catch (error) {
                return ErrCode.SYSTEM_FAIL;
            }
        }else{//update
            partner.name = info.name;
            partner.typeId = info.typeId;
            
            partner.min = info.min;
            partner.max = info.max;
            partner.joinFee = info.joinFee;
            partner.des = info.des;
            partner.thumbnailImage = JSON.stringify(info.thumbnailImage);
            partner.detailsImage = JSON.stringify(info.detailsImage);

            partner.groupEnable = info.groupEnable;
            partner.groupNum = info.groupNum;
            partner.groupAging = info.groupAging;
            try {
                await partnerRep.save(partner);
                return ErrCode.SYSTEM_SUCCESS;
            } catch (error) {
                return ErrCode.SYSTEM_FAIL;
            }
            // return ErrCode.Partner_ADD_NAME_REPEAT;
        }
    }

    /**更新项目状态 */
     public async updatePartnerStatus(partnerid:number,status:PartnerStatus):Promise<any>{
        let partnerRep:Repository<PartnerInfo> = await this.Repository({entities:PartnerInfo});
        let partner:PartnerInfo = await this.getPartnerById({partnerid:partnerid});
        if(partner != null){
            partner.status = status;
            try {
                partnerRep.save(partner);
                return ErrCode.SYSTEM_SUCCESS;
            } catch (error) {
                return ErrCode.SYSTEM_FAIL;
            }
        }else{
            return ErrCode.PARTNER_NOT_FOUND;
        }
    }

     public async getPartnerList(paging:IPagingData):Promise<PartnerInfo[]>{
        let partners:Repository<PartnerInfo> = await this.Repository({entities:PartnerInfo});
        let list:PartnerInfo[] = await partners.find({order:{id:'desc'},where:{status:PartnerStatus.Ongoing},skip:((paging.page-1)*paging.limit),take:paging.limit});
        for(let i in list){
            delete list[i].detailsImage;
        }
        return list;
    }
     public async getPartnerListByStatus(paging:IPagingData,status:PartnerStatus):Promise<PartnerInfo[]>{
        let partnerRep:Repository<PartnerInfo> = await this.Repository({entities:PartnerInfo});
        let list:PartnerInfo[] = await partnerRep.find({order:{id:'desc'},where:{status:status},skip:((paging.page-1)*paging.limit),take:paging.limit});
        // for(let i in list){
        //     delete list[i].detailsImage;
        // }
        return list;
    }

     public async getPartnerById(data:QueryPartnerDTO):Promise<PartnerInfo>{
        let partners:Repository<PartnerInfo> = await this.Repository({entities:PartnerInfo});
        let list:PartnerInfo = await partners.findOne({where:{id:data.partnerid}});
        return list;
    }
    public async getPartnerByIds(ids:number[]):Promise<PartnerInfo[]>{
        let partners:Repository<PartnerInfo> = await this.Repository({entities:PartnerInfo});
        let list:PartnerInfo[] = await partners.find({where:{id:In(ids)}});
        return list;
    }
    public async refundPartner(partnerid:number,userids:number[]):Promise<any>{
        let partnerRep:Repository<PartnerInfo> = await this.Repository({entities:PartnerInfo});
        let partnerlist:PartnerInfo = await partnerRep.findOne({select:['joinFee'],where:{id:(partnerid)}});
        if(partnerlist != null){
            let fee = parseInt(partnerlist.joinFee + '');
            let addResult:ErrCode = await this.userService.AddCurrency(userids,fee);
            if(addResult == ErrCode.SYSTEM_SUCCESS){
                return await this.userService.AddCurrencyUseLog(userids,fee,CurrencyLogType.Refund,partnerid);
            }
            return addResult;
        }
        return ErrCode.PARTNER_NOT_FOUND;
    }
     public async joinPartner(userid:number,serialNo:string,appendData:number,appendType:UserAddendType):Promise<ErrCode|IJsapiClientPay|IWechatErrResult>{
        let partnerRep:Repository<PartnerInfo> = await this.Repository({entities:PartnerInfo});
        let partner:PartnerInfo = await partnerRep.findOne({select:['id','joinFee','min','max','now'],where:{serialNo:serialNo,status:PartnerStatus.Ongoing}});
        if(partner != null){
            if(partner.now < partner.max){
                //扣除合伙点( 记录扣点记录)
                let currency:number = await this.userService.GetCurrency(userid);
                if(currency > 0 && currency >= partner.joinFee){    
                    //记录扣除点
                    await this.addUserPartner(partner.id,userid,UserPartnerStatus.Paid,appendData,appendType);
                    const rResult:ErrCode = await this.userService.ReduceCurrency(userid,partner.joinFee);
                    if(rResult == ErrCode.SYSTEM_SUCCESS){
                        return await this.userService.AddCurrencyUseLog([userid],partner.joinFee,CurrencyLogType.Partner_join,partner.id);
                    }
                    return rResult;
                }else{
                    let config:IBaseConfig = await this.systemConfig.getSystemConfig(SystemConfigType.Base_Config);
                    let price = (partner.joinFee - currency)/config.Recharge_base_ratio; 
                    await this.addUserPartner(partner.id,userid,UserPartnerStatus.Wait_Paid,appendData,appendType);
                    return await this.wechatPay.paid(userid,partner.id,price,partner.name);
                }
            }else{
                return ErrCode.Partner_JOIN_FULL;
            }
        }else{
            return ErrCode.Partner_JOIN_FAIL;
        }
    }

    public async CheckPartnerUser(userid:number):Promise<boolean>{
        let userPartnerList:UserPartner[] = await this.getUserPartnerByStatus(userid,UserPartnerStatus.Paid);
        let baseconfig:IBaseConfig = await this.systemConfig.getSystemConfig(SystemConfigType.Base_Config);
        if(baseconfig.joinProjectsNum > userPartnerList.length){
            return true;
        }
        return false;
    }

     public async openGroup(userid:number,partnerid:number,userAddendType:UserAddendType = UserAddendType.OpenGroup):Promise<ErrCode|IJsapiClientPay|IWechatErrResult>{
        let groupRep:Repository<partnerGroupBuy> = await this.Repository({entities:partnerGroupBuy});
        let partnerInfo:PartnerInfo = await this.getPartnerById({partnerid:partnerid});
        if(partnerInfo != null && await this.CheckPartnerUser(userid)){
             let group:partnerGroupBuy = new partnerGroupBuy();
             group.openUserid = userid;
             group.userids = userid+"";
             group.partnerid = partnerid;

             group.clustersNum = partnerInfo.groupNum;
             group.currentNum = 1;
             group.addtime = Tools.timestamp;
             group.endtime = Tools.timestamp + (partnerInfo.groupAging * 60);
             try {
                const result:ErrCode|IJsapiClientPay|IWechatErrResult = await this.joinPartner(userid,partnerInfo.serialNo,0,userAddendType);
                if((result as ErrCode) == ErrCode.SYSTEM_SUCCESS){
                   group.status = PartnerGroupStatus.Ongoing;
                }else{
                    group.status = PartnerGroupStatus.Wait_paid;
                }
                await groupRep.insert(group);
                return result;
             } catch (error) {
                return ErrCode.SYSTEM_FAIL;
             }
        }else{
            return ErrCode.PARTNER_GROUP_INVOLVED;
        }
    }

     public async joinGroupByid(userid:number,groupid:number,userAddendType:UserAddendType = UserAddendType.OpenGroup):Promise<ErrCode|IJsapiClientPay|IWechatErrResult>{
        let groupRep:Repository<partnerGroupBuy> = await this.Repository({entities:partnerGroupBuy});
        let groupinfo:partnerGroupBuy = await groupRep.findOne({where:{id:groupid,status:PartnerGroupStatus.Ongoing}});
        if(groupinfo != null){
            if(!await this.CheckPartnerUser(userid)){
                return ErrCode.PARTNER_GROUP_INVOLVED;
            }
            let partnerInfo:PartnerInfo = await this.getPartnerById({partnerid:groupinfo.partnerid});
            try {
                let result:ErrCode|IJsapiClientPay|IWechatErrResult = await this.joinPartner(userid,partnerInfo.serialNo,groupinfo.id,userAddendType);
                if((result as ErrCode) == ErrCode.SYSTEM_SUCCESS){
                    groupinfo.userids += ","+userid;
                    groupinfo.currentNum += 1;
                    await groupRep.save(groupinfo);
                    if(groupinfo.currentNum == groupinfo.clustersNum){//人数已满，结束拼团.
                        return await this.HandleGroupStatus(groupinfo.id,PartnerGroupStatus.Finish);
                        //通知 用户参加群里或前往某地参加会议
                        
                    }
                }
                return result;
            } catch (error) {
                return ErrCode.SYSTEM_FAIL;
            }
        }else{
            return ErrCode.PARTNER_GROUP_NOT_FOUND;
        }
    }
     public async joinGroup(userid:number,partnerid:number):Promise<ErrCode|IJsapiClientPay|IWechatErrResult>{
        if(!await this.CheckPartnerUser(userid)){
            return ErrCode.PARTNER_GROUP_INVOLVED;
        }else{
            let partnerInfo:PartnerInfo = await this.getPartnerById({partnerid:partnerid});
            if(partnerInfo.status == PartnerStatus.Ongoing){
                let groupRep:Repository<partnerGroupBuy> = await this.Repository({entities:partnerGroupBuy});
                let grouplist:partnerGroupBuy[] = await groupRep.find({where:{partnerid:partnerInfo.id,status:PartnerGroupStatus.Ongoing}});
                grouplist.sort((a:partnerGroupBuy,b:partnerGroupBuy)=>{
                    return b.currentNum - a.currentNum;
                });
                if(grouplist.length > 0){
                    let maxgroup:partnerGroupBuy = grouplist[0];
                    return await this.joinGroupByid(userid,maxgroup.id);  
                }else{
                    return await this.openGroup(userid,partnerid);
                }
            }else{
                return ErrCode.PARTNER_INFO_END;
            }
        }
    }

     public async getGroupByPartnerid(partnerid:number):Promise<partnerGroupBuy[]>{
        let groupRep:Repository<partnerGroupBuy> = await this.Repository({entities:partnerGroupBuy});
        let grouplist:partnerGroupBuy[] = await groupRep.find({where:{partnerid:partnerid,status:PartnerGroupStatus.Ongoing}});
        return grouplist;
    }

    public async getGroupByStatus(paging:IPagingData,status:PartnerGroupStatus):Promise<partnerGroupBuy[]>{
        let partnerRep:Repository<partnerGroupBuy> = await this.Repository({entities:partnerGroupBuy});
        let list:partnerGroupBuy[] = await partnerRep.find({order:{id:'desc'},where:{status:status},skip:((paging.page-1)*paging.limit),take:paging.limit});
        return list;
    }
    
    public async HandleGroupStatus(groupid:number,status:PartnerGroupStatus):Promise<ErrCode>{
        let partnerRep:Repository<partnerGroupBuy> = await this.Repository({entities:partnerGroupBuy});
        let groupInfo:partnerGroupBuy = await partnerRep.findOne({select:['status','userids','partnerid','id'],where:{id:groupid}});
        if(groupInfo != null){
            if(groupInfo.status != status){
                groupInfo.status = status;
                let userids:number[] = groupInfo.userids.split(',').map(Number);
                try {
                    await partnerRep.save(groupInfo);
                    if(status == PartnerGroupStatus.Ended){
                        await this.updateUserPartnerStatus(userids,groupInfo.partnerid,UserPartnerStatus.Refund,UserPartnerStatus.Paid);
                        return await this.refundPartner(groupInfo.partnerid,userids);
                    }
                    await this.updateUserPartnerStatus(userids,groupInfo.partnerid,UserPartnerStatus.Finish,UserPartnerStatus.Paid);
                    return ErrCode.SYSTEM_SUCCESS;
                } catch (error) {
                    return ErrCode.SYSTEM_FAIL;
                }
            }
            return ErrCode.PARTNER_GROUP_END;
        }else{
            return ErrCode.PARTNER_GROUP_NOT_FOUND;
        }
    }
}